﻿/*******************************************************************
 *     JameE
 *******************************************************************
  Copyright 2010 Clifford Champion and JameE contributors.
  
  This file is part of JameE.
  
  JameE is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  JameE is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with JameE.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************/
 
 
/// <reference path="~/Base/Classer.js" />
/// <reference path="~/Base/IncludeLoader.js" />

$class(
"JameE.Math.Vector3",
{
	/////////////////////
	// FIELDS
	/////////////
	fX: 0.0,
	fY: 0.0,
	fZ: 0.0,


	/////////////////////
	// CONSTRUCTOR
	/////////////
	_ctor: function (args) {
		this.fX = $argument("x", "number") || 0.0;
		this.fY = $argument("y", "number") || 0.0;
		this.fZ = $argument("z", "number") || 0.0;
	},


	/////////////////////
	// METHODS
	/////////////
	magnitude: function () {
		return Math.sqrt(this.magnitudeSquared());
	},

	magnitudeSquared: function () {
		var fX = this.fX;
		var fY = this.fY;
		var fZ = this.fZ;
		return fX * fX + fY * fY + fZ * fZ;
	},

	innerProduct: function (oOtherVector) {
		var fProduct
			= oOtherVector.fX * this.fX
			+ oOtherVector.fY * this.fY
			+ oOtherVector.fZ * this.fZ;
		return fProduct;
	},

	equals: function (oOtherVector) {
		if (oOtherVector.fX === this.fX
			&& oOtherVector.fY === this.fY
			&& oOtherVector.fZ === this.fZ) {
			return true;
		}
		else {
			return false;
		}
	},

	equalsApproximately: function (fX, fY, fZ, fError) {
		/// <summary>Checks one or more components of the
		/// vector for equality within an error size.</summary>

		$require_type_null(fX, "number");
		$require_type_null(fY, "number");
		$require_type_null(fZ, "number");
		$require_type_null(fError, "number");

		fError = fError || 0.01;

		if (fX !== null && Math.abs(fX - this.fX) > fError) {
			return false;
		}
		if (fY !== null && Math.abs(fY - this.fY) > fError) {
			return false;
		}
		if (fZ !== null && Math.abs(fZ - this.fZ) > fError) {
			return false;
		}
		return true;
	},

	transform: function (oMatrix33) {
		/// <summary>Returns a new vector by transforming
		/// the current vector by the given matrix. Uses
		/// z = 1 to enable translations.
		/// </summary>
		$require_type(oMatrix33, "JameE.Math.Matrix");
		if (oMatrix33.getNumRows() !== 3 || oMatrix33.getNumColumns() !== 3) {
			throw new Error("Matrix dimensions must be 3x3");
		}
		var oResult = new JameE.Math.Vector3();

		oResult.fX
			= oMatrix33.getValue(0, 0) * this.fX
			+ oMatrix33.getValue(0, 1) * this.fY
			+ oMatrix33.getValue(0, 2) * 1
		;
		oResult.fY
			= oMatrix33.getValue(1, 0) * this.fX
			+ oMatrix33.getValue(1, 1) * this.fY
			+ oMatrix33.getValue(1, 2) * 1
		;
		oResult.fZ = this.fZ;

		return oResult;
	},

	normalize: function () {
		/// <summary>Returns a normalized version of this vector.</summary>

		var fMagSquared = this.magnitudeSquared();

		if (fMagSquared < 0.000001) { // return zero vector.
			return new JameE.Math.Vector3();
		}

		var fMag = Math.sqrt(fMagSquared);
		var oResult = new JameE.Math.Vector3(
			{
				x: this.fX / fMag,
				y: this.fY / fMag,
				z: this.fZ / fMag
			}
		);

		return oResult;
	},

	add: function (oOtherVector) {
		$require_type(oOtherVector, "Math.Vector3");

		var oResult = new JameE.Math.Vector3(
			{
				x: oOtherVector.fX + this.fX,
				y: oOtherVector.fY + this.fY,
				z: oOtherVector.fZ + this.fZ
			}
		);
		return oResult;
	},

	subtract: function (oOtherVector) {
		$require_type(oOtherVector, "Math.Vector3");

		var oResult = new JameE.Math.Vector3(
			{
				x: this.fX - oOtherVector.fX,
				y: this.fY - oOtherVector.fY,
				z: this.fZ - oOtherVector.fZ
			}
		);
		return oResult;
	},

	multiply: function (fScalar) {
		$require_type(fScalar, "number");

		var oResult = new JameE.Math.Vector3(
			{
				x: fScalar * this.fX,
				y: fScalar * this.fY,
				z: fScalar * this.fZ
			}
		);
		return oResult;
	}
});


/////////////////////
// METHODS SHORTCUTS
/////////////
$vector3 = function(x, y, z) { return new JameE.Math.Vector3({ x: x, y: y, z: z }); };


$include_notify("Math/Vector3.js");
